/*
a simple html web server work with node.js
http://yoyo.play175.com/
*/
var PORT = 80;
var DOCROOT = "./";
var OPENINDEX = true;

var http = require("http");
var url = require("url");
var fs = require("fs");
var path = require("path");
var zlib = require("zlib");

var config = {
	Expires : {
		fileMatch: /^(gif|png|jpg|js|css)$/ig,
		maxAge: 60*60*24*365
	},
	Compress : {
		match: /css|js|html/ig
	},
	Welcome : {
		file: "index.html"
	}
};
var mime = { ".3gp"   : "video/3gpp"
  , ".a"     : "application/octet-stream"
  , ".ai"    : "application/postscript"
  , ".aif"   : "audio/x-aiff"
  , ".aiff"  : "audio/x-aiff"
  , ".asc"   : "application/pgp-signature"
  , ".asf"   : "video/x-ms-asf"
  , ".asm"   : "text/x-asm"
  , ".asx"   : "video/x-ms-asf"
  , ".atom"  : "application/atom+xml"
  , ".au"    : "audio/basic"
  , ".avi"   : "video/x-msvideo"
  , ".bat"   : "application/x-msdownload"
  , ".bin"   : "application/octet-stream"
  , ".bmp"   : "image/bmp"
  , ".bz2"   : "application/x-bzip2"
  , ".c"     : "text/x-c"
  , ".cab"   : "application/vnd.ms-cab-compressed"
  , ".cc"    : "text/x-c"
  , ".chm"   : "application/vnd.ms-htmlhelp"
  , ".class"   : "application/octet-stream"
  , ".com"   : "application/x-msdownload"
  , ".conf"  : "text/plain"
  , ".cpp"   : "text/x-c"
  , ".crt"   : "application/x-x509-ca-cert"
  , ".css"   : "text/css"
  , ".csv"   : "text/csv"
  , ".cxx"   : "text/x-c"
  , ".deb"   : "application/x-debian-package"
  , ".der"   : "application/x-x509-ca-cert"
  , ".diff"  : "text/x-diff"
  , ".djv"   : "image/vnd.djvu"
  , ".djvu"  : "image/vnd.djvu"
  , ".dll"   : "application/x-msdownload"
  , ".dmg"   : "application/octet-stream"
  , ".doc"   : "application/msword"
  , ".dot"   : "application/msword"
  , ".dtd"   : "application/xml-dtd"
  , ".dvi"   : "application/x-dvi"
  , ".ear"   : "application/java-archive"
  , ".eml"   : "message/rfc822"
  , ".eps"   : "application/postscript"
  , ".exe"   : "application/x-msdownload"
  , ".f"     : "text/x-fortran"
  , ".f77"   : "text/x-fortran"
  , ".f90"   : "text/x-fortran"
  , ".flv"   : "video/x-flv"
  , ".for"   : "text/x-fortran"
  , ".gem"   : "application/octet-stream"
  , ".gemspec" : "text/x-script.ruby"
  , ".gif"   : "image/gif"
  , ".gz"    : "application/x-gzip"
  , ".h"     : "text/x-c"
  , ".hh"    : "text/x-c"
  , ".htm"   : "text/html"
  , ".html"  : "text/html"
  , ".ico"   : "image/vnd.microsoft.icon"
  , ".ics"   : "text/calendar"
  , ".ifb"   : "text/calendar"
  , ".iso"   : "application/octet-stream"
  , ".jar"   : "application/java-archive"
  , ".java"  : "text/x-java-source"
  , ".jnlp"  : "application/x-java-jnlp-file"
  , ".jpeg"  : "image/jpeg"
  , ".jpg"   : "image/jpeg"
  , ".js"    : "application/javascript"
  , ".json"  : "application/json"
  , ".log"   : "text/plain"
  , ".m3u"   : "audio/x-mpegurl"
  , ".m4v"   : "video/mp4"
  , ".man"   : "text/troff"
  , ".mathml"  : "application/mathml+xml"
  , ".mbox"  : "application/mbox"
  , ".mdoc"  : "text/troff"
  , ".me"    : "text/troff"
  , ".mid"   : "audio/midi"
  , ".midi"  : "audio/midi"
  , ".mime"  : "message/rfc822"
  , ".mml"   : "application/mathml+xml"
  , ".mng"   : "video/x-mng"
  , ".mov"   : "video/quicktime"
  , ".mp3"   : "audio/mpeg"
  , ".mp4"   : "video/mp4"
  , ".mp4v"  : "video/mp4"
  , ".mpeg"  : "video/mpeg"
  , ".mpg"   : "video/mpeg"
  , ".ms"    : "text/troff"
  , ".msi"   : "application/x-msdownload"
  , ".odp"   : "application/vnd.oasis.opendocument.presentation"
  , ".ods"   : "application/vnd.oasis.opendocument.spreadsheet"
  , ".odt"   : "application/vnd.oasis.opendocument.text"
  , ".ogg"   : "application/ogg"
  , ".p"     : "text/x-pascal"
  , ".pas"   : "text/x-pascal"
  , ".pbm"   : "image/x-portable-bitmap"
  , ".pdf"   : "application/pdf"
  , ".pem"   : "application/x-x509-ca-cert"
  , ".pgm"   : "image/x-portable-graymap"
  , ".pgp"   : "application/pgp-encrypted"
  , ".pkg"   : "application/octet-stream"
  , ".pl"    : "text/x-script.perl"
  , ".pm"    : "text/x-script.perl-module"
  , ".png"   : "image/png"
  , ".pnm"   : "image/x-portable-anymap"
  , ".ppm"   : "image/x-portable-pixmap"
  , ".pps"   : "application/vnd.ms-powerpoint"
  , ".ppt"   : "application/vnd.ms-powerpoint"
  , ".ps"    : "application/postscript"
  , ".psd"   : "image/vnd.adobe.photoshop"
  , ".py"    : "text/x-script.python"
  , ".qt"    : "video/quicktime"
  , ".ra"    : "audio/x-pn-realaudio"
  , ".rake"  : "text/x-script.ruby"
  , ".ram"   : "audio/x-pn-realaudio"
  , ".rar"   : "application/x-rar-compressed"
  , ".rb"    : "text/x-script.ruby"
  , ".rdf"   : "application/rdf+xml"
  , ".roff"  : "text/troff"
  , ".rpm"   : "application/x-redhat-package-manager"
  , ".rss"   : "application/rss+xml"
  , ".rtf"   : "application/rtf"
  , ".ru"    : "text/x-script.ruby"
  , ".s"     : "text/x-asm"
  , ".sgm"   : "text/sgml"
  , ".sgml"  : "text/sgml"
  , ".sh"    : "application/x-sh"
  , ".sig"   : "application/pgp-signature"
  , ".snd"   : "audio/basic"
  , ".so"    : "application/octet-stream"
  , ".svg"   : "image/svg+xml"
  , ".svgz"  : "image/svg+xml"
  , ".swf"   : "application/x-shockwave-flash"
  , ".t"     : "text/troff"
  , ".tar"   : "application/x-tar"
  , ".tbz"   : "application/x-bzip-compressed-tar"
  , ".tcl"   : "application/x-tcl"
  , ".tex"   : "application/x-tex"
  , ".texi"  : "application/x-texinfo"
  , ".texinfo" : "application/x-texinfo"
  , ".text"  : "text/plain"
  , ".tif"   : "image/tiff"
  , ".tiff"  : "image/tiff"
  , ".torrent" : "application/x-bittorrent"
  , ".tr"    : "text/troff"
  , ".txt"   : "text/plain"
  , ".vcf"   : "text/x-vcard"
  , ".vcs"   : "text/x-vcalendar"
  , ".vrml"  : "model/vrml"
  , ".war"   : "application/java-archive"
  , ".wav"   : "audio/x-wav"
  , ".wma"   : "audio/x-ms-wma"
  , ".wmv"   : "video/x-ms-wmv"
  , ".wmx"   : "video/x-ms-wmx"
  , ".wrl"   : "model/vrml"
  , ".wsdl"  : "application/wsdl+xml"
  , ".xbm"   : "image/x-xbitmap"
  , ".xhtml"   : "application/xhtml+xml"
  , ".xls"   : "application/vnd.ms-excel"
  , ".xml"   : "application/xml"
  , ".xpm"   : "image/x-xpixmap"
  , ".xsl"   : "application/xml"
  , ".xslt"  : "application/xslt+xml"
  , ".yaml"  : "text/yaml"
  , ".yml"   : "text/yaml"
  , ".zip"   : "application/zip"
};

var server = http.createServer(function(request, response) {
    response.setHeader("Server", "Fastiny");
    var pathname = url.parse(request.url).pathname;
    pathname = decodeURIComponent(pathname);
    var dir = null;
    if (pathname.slice(-1) === "/") {
        dir = path.join(DOCROOT, path.normalize(pathname.replace(/\.\./g, "")));
        pathname = pathname + config.Welcome.file;
    }
    var realPath = path.join(DOCROOT, path.normalize(pathname.replace(/\.\./g, "")));

    var pathHandle = function (realPath,dirpath) {
        fs.stat(realPath, function (err, stats) {
            if (err) {
                if(OPENINDEX && dirpath!=null) {
                    if (dirpath.slice(-1) != '\\' && dirpath.slice(-1) != '/') {
                      response.writeHead(301, "", {
                         'Location': dirpath+'\\'
                        ,'Cache-Control' : 'no-cache, must-revalidate'
                        ,'Pragma' : 'no-cache'
                      });
                      response.end();
                      return;
                    }
                   var body = getFilesDesc(dirpath);
                    response.writeHead(200, {
                      'Content-Type': 'text/html; charset=utf-8'
                      ,'Cache-Control' : 'no-cache, must-revalidate'
                      ,'Pragma' : 'no-cache'
                    });
                    response.end(body);
                }else {
                  response.writeHead(404, "Not Found", {'Content-Type': 'text/plain'});
                  response.write("This request URL " + pathname + " was not found on this server.");
                  response.end();
                }
            } else {
                if (stats.isDirectory()) {
                    var dir = realPath + '';
                    realPath = path.join(realPath, "/", config.Welcome.file);                    
                    pathHandle(realPath,dir);
                } else {
                    var ext = path.extname(realPath);
                    ext = ext ? ext : 'unknown';
                    var contentType = mime[ext] || "text/plain";
                    console.log(''+mime[ext]);
                    response.setHeader("Content-Type", contentType);

                    var lastModified = stats.mtime.toUTCString();
                    var ifModifiedSince = "If-Modified-Since".toLowerCase();
                    response.setHeader("Last-Modified", lastModified);

                    if (ext.match(config.Expires.fileMatch)) {
                        var expires = new Date();
                        expires.setTime(expires.getTime() + config.Expires.maxAge * 1000);
                        response.setHeader("Expires", expires.toUTCString());
                        response.setHeader("Cache-Control", "max-age=" + config.Expires.maxAge);
                    }

                    if (request.headers[ifModifiedSince] && lastModified == request.headers[ifModifiedSince]) {
                        response.writeHead(304, "Not Modified");
                        response.end();
                    } else {
                        var raw = fs.createReadStream(realPath);
                        var acceptEncoding = request.headers['accept-encoding'] || "";
                        var matched = ext.match(config.Compress.match);

                        if (matched && acceptEncoding.match(/\bgzip\b/)) {
                            response.writeHead(200, "Ok", {'Content-Encoding': 'gzip'});
                            raw.pipe(zlib.createGzip()).pipe(response);
                        } else if (matched && acceptEncoding.match(/\bdeflate\b/)) {
                            response.writeHead(200, "Ok", {'Content-Encoding': 'deflate'});
                            raw.pipe(zlib.createDeflate()).pipe(response);
                        } else {
                            response.writeHead(200, "Ok");
                            raw.pipe(response);
                        }
                    }
                }
            }
        });
    };
    var getFilesDesc = function(dirpath) {
      try{
        var farr = fs.readdirSync(dirpath);
      }catch(e){
          return '404,Not Found';
        }
        var out = '<!DOCTYPE html><html><head><title id="title"></title></head><body>';

        if(dirpath[0] == '.')dirpath = dirpath.substr(1,dirpath.length-1);
        if(dirpath[0] != '\\')dirpath = '\\' + dirpath;
        dirpath = dirpath.replace(/\\/g,'/');
        out += '<h3>'+dirpath+'</h3><hr />';

        out += '<dl>';
        if(dirpath!='/')out += '<li><a href="../">[上级目录]</a></li>';
        for (var i = 0; i < farr.length; i++) {
          var url = farr[i];
          var stats = fs.statSync(path.join(DOCROOT, path.normalize(dirpath),url));
          if(stats.isDirectory())url += '/';
          out += '<li><a href="'+url+'">'+url+'</a></li>';
        }
        out += '</dl>';
        out += '</body></html>';
        return out;
    };
    pathHandle(realPath,dir);
});

server.listen(PORT);
console.log("Server runing at port: " + PORT + ".");
